﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//    OutlookApplication.cs
//
// Abstract:
//    
//    Implements the IOutlookApplication interface using Outlook Application data.
//
//--

using System;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Office.Interop.Outlook;

namespace Microsoft.EnhancedReminders.OutlookAddIn
{
    /// <summary>
    /// Implements the IApplication interface using Outlook Application data
    /// </summary>
    public sealed class OutlookApplication : IOutlookApplication
    {
        private Application _application;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="application">Outlook Application interface</param>
        public OutlookApplication(Application application)
        {
            Debug.Assert(application != null, "application != null");
            _application = application;
        }

        #region IApplication Members

        /// <summary>
        /// Gets the storage item used to store rules and channel data.
        /// </summary>
        /// <returns>The storage item or null if the storage item cannot be accessed.</returns>
        public IStorageItem GetStorageItem()
        {
            IStorageItem storageItem = null;

            // Search the inbox for the storage item folder
            MAPIFolder storageFolder = FindStorageFolder(_application.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox));

            // Search for the storage item in the storage item folder
            MailItem mailItem = FindStorageItem(storageFolder);

            if (mailItem == null && IsOnline)
            {
                if (storageFolder == null)
                {
                    storageFolder = CreateStorageFolder();
                }

                // Create a new storage item if a valid one doesn't already exist and Outlook is on-line
                mailItem = storageFolder.Items.Add(OlItemType.olMailItem) as MailItem;

                if (mailItem != null)
                {
                    // Make sure it doesn't show up in the unread messages folder
                    mailItem.UnRead = false;

                    // Set the subject to indicate this is the storage item
                    mailItem.Subject = Constants.StorageItemName;

                    // Attach the default data object to the new storage item
                    OutlookUtils.SaveAttachment(mailItem.Attachments, OutlookUtils.CreateDefaultStorageData());

                    // Save the storage item
                    mailItem.Move(storageFolder);
                }
            }

            if (mailItem != null)
            {
                // Create wrapper
                storageItem = new OutlookStorageItem(mailItem);
            }

            return storageItem;
        }

        /// <summary>
        /// Deletes the storage item used for storing data (if it exists).
        /// </summary>
        public void DeleteStorageItem()
        {
            // Find the storage item folder
            MAPIFolder storageFolder = FindStorageFolder(_application.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox));

            if (storageFolder != null)
            {
                // Delete the folder
                storageFolder.Delete();
            }
        }

        #endregion

        /// <summary>
        /// Finds the storage item.
        /// </summary>
        /// <returns>Storage item or null if one cannot be found</returns>
        private static MailItem FindStorageItem(MAPIFolder folder)
        {
            if (folder != null)
            {
                // Storage items are identified by a specific subject
                Items items = folder.Items.Restrict(String.Format(CultureInfo.InvariantCulture, "[Subject] = '{0}'", Constants.StorageItemName));

                if (items != null)
                {
                    foreach (MailItem mailItem in items)
                    {
                        if (OutlookStorageItem.IsValidStorageItem(mailItem))
                        {
                            // Return the first valid storage item
                            return mailItem;
                        }
                    }
                }
            }

            // No valid storage item was found
            return null;
        }

        /// <summary>
        /// Find the storage item parent folder.
        /// </summary>
        /// <param name="folder">Parent of the storage item folder</param>
        /// <returns>The storage item parent folder or null if the folder can't be found.</returns>
        private static MAPIFolder FindStorageFolder(MAPIFolder folder)
        {
            if (folder != null)
            {
                foreach (MAPIFolder subFolder in folder.Folders)
                {
                    if (subFolder.Name == Constants.StorageItemFolderName)
                    {
                        // Return the first sub-folder with the correct name
                        return subFolder;
                    }
                }
            }

            // The storage folder was not found
            return null;
        }

        /// <summary>
        /// Indicates if Outlook is currently connected.
        /// </summary>
        private bool IsOnline
        {
            get
            {
                return _application.Session.ExchangeConnectionMode == OlExchangeConnectionMode.olCachedConnectedDrizzle |
                _application.Session.ExchangeConnectionMode == OlExchangeConnectionMode.olCachedConnectedFull |
                _application.Session.ExchangeConnectionMode == OlExchangeConnectionMode.olCachedConnectedHeaders |
                _application.Session.ExchangeConnectionMode == OlExchangeConnectionMode.olOnline;
            }
        }

        /// <summary>
        /// Creates the Storage Folder used by Enhanced Reminders.
        /// </summary>
        private MAPIFolder CreateStorageFolder()
        {
            // Create the storage item folder if it doesn't already exist and Outlook is on-line
            MAPIFolder storageFolder = _application.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox).Folders.Add(Constants.StorageItemFolderName, "IPF.Note");

            // Make the folder hidden
            storageFolder.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x10F4000B", true);

            // Ensure the folder is synchronized with Exchange
            storageFolder.InAppFolderSyncObject = true;

            return storageFolder;
        }
    }
}
